/*
Wonderous, magnificant, stupendous EEPROM routines

The slight catch here is that the eeprom is checksum verified but it is possible to write values to the EEPROM
without updating the checksum. That's bad as it invalids the currently stored checksum. If the system resets while
still in this state then the eeprom will be considered invalid and all values reset. So either checksumming
should be disabled or a scheme devised to update the checksum periodically. Maybe a backup eeprom copy could be made
and the backup restored on checksum failure? That seems sort of drastic but maybe...
*/

#include "settings.h"
#include "AC-Controller.h"
#include "globals.h"
#include "eeprom.h"

//defines for what stuff is stored in EEPROM
//EEPROM is accessed as 16 bit integers on this processor
//so plan accordingly

//a 16 bit checksum of the rest of EEPROM contents
int _EEDATA(2) EEPROM_CHECKSUM;

//a bitfield of devices to use
//bit:
//0		Main Contactor
//1		Precharge Contactor/Resistor
//2		Encoder
//3		Potentiometer throttle
//4		HEPA/HETA throttle
//5		CANBus remote control
//6		Motor temperature sensor
//7		Controller temperature sensor
int _EEDATA(2) EEPROM_USE_DEVICES;
int _EEDATA(2) EEPROM_THROTTLE_MIN; //for pot throttle min ADC reading to be valid
int _EEDATA(2) EEPROM_THROTTLE_MAX; //for pot throttle max ADC reading to be valid
int _EEDATA(2) EEPROM_PRECHARGE_TIME; //max precharge time in ms
int _EEDATA(2) EEPROM_ROTOR_TIME_CONST; //rotor time constant in 1/10th of a ms
int _EEDATA(2) EEPROM_MOTOR_POLES; //how many pole pairs
int _EEDATA(2) EEPROM_ENCODER_COUNT; //# of counts per revolution
int _EEDATA(2) EEPROM_CURRENT_GAIN; //gain of current sensor - how many amps one ADC value represents in .1 amps
int _EEDATA(2) EEPROM_CURRENT_BIAS;	 //ADC reading at 0 current (from 0 - 1023)
int _EEDATA(2) EEPROM_VOLTAGE_GAIN; //gain of HV sense input - how many volts one ADC value is in .1 Volts
int _EEDATA(2) EEPROM_MAX_VOLT;	 //maximum voltage we want to accept
int _EEDATA(2) EEPROM_MIN_VOLT;	 //minimum voltage we're prepared to accept
int _EEDATA(2) EEPROM_MOTOR_VOLT; //how many volts the motor is rated for
int _EEDATA(2) EEPROM_MOTOR_HERTZ; //how many hertz the motor is rated for
int _EEDATA(2) EEPROM_MAX_AMPS;	 //maximum amperage to allow on output
int _EEDATA(2) EEPROM_OVERHEAT_CTRL; //number of times the controller has hit thermal limit
int _EEDATA(2) EEPROM_OVERHEAT_MOTOR; //number of times the motor has hit thermal limit
int _EEDATA(2) EEPROM_LAST_FAULTS;	 //bitfield of last faults we saw
int _EEDATA(2) EEPROM_CANBUS_SPEED; //speed of canbus
//0 = 1M baud
//1 = 500k baud
//2 = 250k Baud
//3 = 125K Baud
//4 = 62.5k baud
int _EEDATA(2) EEPROM_CANBUS_ID_L; //lower 16 bits
int _EEDATA(2) EEPROM_CANBUS_ID_H; //upper 13 bits

_prog_addressT tempLoc;

//the functions which actually touch the EEPROM
void write_eeprom(_prog_addressT location, int value) {
	_erase_eedata(location, _EE_WORD);
	_wait_eedata();
	_write_eedata_word(location, value);	
	_wait_eedata();
}

int read_eeprom(_prog_addressT location) {
	int temp;
	_memcpy_p2d16(&temp, location, 2);
	return temp;
}

//a bunch of syntactic sugar to make it simpler for every other function to get
//and set values in EEPROM without having to deal with the nitty gritty details
//as a bonus these functions could do checks to make sure values are proper. But, right
//now they're dumb. They just get and set what they are told.
int ee_get_checksum(void) {
	_init_prog_address(tempLoc,EEPROM_CHECKSUM);
	return(read_eeprom(tempLoc));
}

void ee_set_checksum(int newval) {
	_init_prog_address(tempLoc,EEPROM_CHECKSUM);
	write_eeprom(tempLoc, newval);
}

int ee_get_use_devices(void) {
	_init_prog_address(tempLoc,EEPROM_USE_DEVICES);
	return(read_eeprom(tempLoc));
}

void ee_set_use_devices(int newval) {
	_init_prog_address(tempLoc,EEPROM_USE_DEVICES);
	write_eeprom(tempLoc, newval);
}

int ee_get_throttle_min(void) {
	_init_prog_address(tempLoc,EEPROM_THROTTLE_MIN);
	return(read_eeprom(tempLoc));
}

void ee_set_throttle_min(int newval) {
	_init_prog_address(tempLoc,EEPROM_THROTTLE_MIN);
	write_eeprom(tempLoc, newval);
}

int ee_get_throttle_max(void) {
	_init_prog_address(tempLoc,EEPROM_THROTTLE_MAX);
	return(read_eeprom(tempLoc));
}

void ee_set_throttle_max(int newval) {
	_init_prog_address(tempLoc,EEPROM_THROTTLE_MAX);
	write_eeprom(tempLoc, newval);
}

int ee_get_precharge_time(void) {
	_init_prog_address(tempLoc,EEPROM_PRECHARGE_TIME);
	return(read_eeprom(tempLoc));
}

void ee_set_precharge_time(int newval) {
	_init_prog_address(tempLoc,EEPROM_PRECHARGE_TIME);
	write_eeprom(tempLoc, newval);
}

int ee_get_rotor_time_const(void) {
	_init_prog_address(tempLoc,EEPROM_ROTOR_TIME_CONST);
	return(read_eeprom(tempLoc));
}

void ee_set_rotor_time_const(int newval) {
	_init_prog_address(tempLoc,EEPROM_ROTOR_TIME_CONST);
	write_eeprom(tempLoc, newval);
}

int ee_get_motor_poles(void) {
	_init_prog_address(tempLoc,EEPROM_MOTOR_POLES);
	return(read_eeprom(tempLoc));
}

void ee_set_motor_poles(int newval) {
	_init_prog_address(tempLoc,EEPROM_MOTOR_POLES);
	write_eeprom(tempLoc, newval);
}

int ee_get_encoder_count(void) {
	_init_prog_address(tempLoc,EEPROM_ENCODER_COUNT);
	return(read_eeprom(tempLoc));
}

void ee_set_encoder_count(int newval) {
	_init_prog_address(tempLoc,EEPROM_ENCODER_COUNT);
	write_eeprom(tempLoc, newval);
}

int ee_get_current_gain(void) {
	_init_prog_address(tempLoc,EEPROM_CURRENT_GAIN);
	return(read_eeprom(tempLoc));
}

void ee_set_current_gain(int newval) {
	_init_prog_address(tempLoc,EEPROM_CURRENT_GAIN);
	write_eeprom(tempLoc, newval);
}

int ee_get_current_bias(void) {\
	_init_prog_address(tempLoc,EEPROM_CURRENT_BIAS);
	return(read_eeprom(tempLoc));
}

void ee_set_current_bias(int newval) {
	_init_prog_address(tempLoc,EEPROM_CURRENT_BIAS);
	write_eeprom(tempLoc, newval);
}

int ee_get_voltage_gain(void) {
	_init_prog_address(tempLoc,EEPROM_VOLTAGE_GAIN);
	return(read_eeprom(tempLoc));
}

void ee_set_voltage_gain(int newval) {
	_init_prog_address(tempLoc,EEPROM_VOLTAGE_GAIN);
	write_eeprom(tempLoc, newval);
}


int ee_get_motor_volt(void) {
	_init_prog_address(tempLoc,EEPROM_MOTOR_VOLT);
	return(read_eeprom(tempLoc));
}

void ee_set_motor_volt(int newval) {
	_init_prog_address(tempLoc,EEPROM_MOTOR_VOLT);
	write_eeprom(tempLoc, newval);
}

int ee_get_motor_hertz(void) {
	_init_prog_address(tempLoc,EEPROM_MOTOR_HERTZ);
	return(read_eeprom(tempLoc));
}

void ee_set_motor_hertz(int newval) {
	_init_prog_address(tempLoc,EEPROM_MOTOR_HERTZ);
	write_eeprom(tempLoc, newval);
}

int ee_get_max_volt(void) {
	_init_prog_address(tempLoc,EEPROM_MAX_VOLT);
	return(read_eeprom(tempLoc));
}

void ee_set_max_volt(int newval) {
	_init_prog_address(tempLoc,EEPROM_MAX_VOLT);
	write_eeprom(tempLoc, newval);
}

int ee_get_min_volt(void) {
	_init_prog_address(tempLoc,EEPROM_MIN_VOLT);
	return(read_eeprom(tempLoc));
}

void ee_set_min_volt(int newval) {
	_init_prog_address(tempLoc,EEPROM_MIN_VOLT);
	write_eeprom(tempLoc, newval);
}

int ee_get_max_amps(void) {
	_init_prog_address(tempLoc,EEPROM_MAX_AMPS);
	return(read_eeprom(tempLoc));
}

void ee_set_max_amps(int newval) {
	_init_prog_address(tempLoc,EEPROM_MAX_AMPS);
	write_eeprom(tempLoc, newval);
}

int ee_get_overheat_ctrl(void) {
	_init_prog_address(tempLoc,EEPROM_OVERHEAT_CTRL);
	return(read_eeprom(tempLoc));
}

void ee_set_overheat_ctrl(int newval) {
	_init_prog_address(tempLoc,EEPROM_OVERHEAT_CTRL);
	write_eeprom(tempLoc, newval);
}

int ee_get_overheat_motor(void) {
	_init_prog_address(tempLoc,EEPROM_OVERHEAT_MOTOR);
	return(read_eeprom(tempLoc));
}

void ee_set_overheat_motor(int newval) {
	_init_prog_address(tempLoc,EEPROM_OVERHEAT_MOTOR);
	write_eeprom(tempLoc, newval);
}

int ee_get_last_faults(void) {
	_init_prog_address(tempLoc,EEPROM_LAST_FAULTS);
	return(read_eeprom(tempLoc));
}

void ee_set_last_faults(int newval) {
	_init_prog_address(tempLoc,EEPROM_LAST_FAULTS);
	write_eeprom(tempLoc, newval);
}

int ee_get_canbus_speed(void) {
	_init_prog_address(tempLoc,EEPROM_CANBUS_SPEED);
	return(read_eeprom(tempLoc));
}

void ee_set_canbus_speed(int newval) {
	_init_prog_address(tempLoc,EEPROM_CANBUS_SPEED);
	write_eeprom(tempLoc, newval);
}

long ee_get_canbus_id(void) {
	long temp;
	_init_prog_address(tempLoc,EEPROM_CANBUS_ID_L);
	temp = read_eeprom(tempLoc);
	_init_prog_address(tempLoc,EEPROM_CANBUS_ID_H);
	temp += (long)read_eeprom(tempLoc) << 16;
	return(temp);
}

void ee_set_canbus_id(long newval) {
	int temp;
	temp = newval & 0xFFFF;
	_init_prog_address(tempLoc,EEPROM_CANBUS_ID_L);
	write_eeprom(tempLoc, temp);
	temp = (newval >> 16);
	_init_prog_address(tempLoc,EEPROM_CANBUS_ID_H);
	write_eeprom(tempLoc, temp);
}

//calls every getter function above and sums every value. At the end you have
//the 16bit checksum for all EEPROM contents. With this we can make sure no one has
//screwed with our settings except this firmware. It prevents corruption or meddling hands
//from doing anything dangerous.
unsigned int ee_calcChecksum(void) {
	unsigned int checksum = 0;
	long temp;
	checksum += ee_get_use_devices();
	checksum += ee_get_throttle_min();
	checksum += ee_get_throttle_max();
	checksum += ee_get_precharge_time();
	checksum += ee_get_rotor_time_const();
	checksum += ee_get_motor_poles();
	checksum += ee_get_encoder_count();
	checksum += ee_get_current_gain();
	checksum += ee_get_current_bias();
	checksum += ee_get_voltage_gain();
	checksum += ee_get_max_volt();
	checksum += ee_get_min_volt();
	checksum += ee_get_motor_volt();
	checksum += ee_get_motor_hertz();
	checksum += ee_get_max_amps();
	checksum += ee_get_overheat_ctrl();
	checksum += ee_get_overheat_motor();
	checksum += ee_get_last_faults();
	checksum += ee_get_canbus_speed();
	temp = ee_get_canbus_id();
	checksum += (temp & 0xFFFF);
	checksum += (temp >> 16);

	return checksum;
}

void ee_save_checksum(void) {
	int temp;
	temp = ee_calcChecksum();
	ee_set_checksum(temp);
}

int ee_verify_checksum(void) {
	int temp = ee_calcChecksum();
	int temp2 = ee_get_checksum();
	if (temp2 == 0) return 0;
	if (temp == temp2) return 1;
	return 0;
}

